package com.meilai.project.service.business.workbench.impl;

import cn.hutool.core.convert.Convert;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.meilai.project.constant.BossUserEnum;
import com.meilai.project.dto.business.workbench.UserYearWeekTargetDTO;
import com.meilai.project.entity.business.contract.ContractApply;
import com.meilai.project.entity.business.customer.CustomerFollow;
import com.meilai.project.entity.business.customer.CustomerInfo;
import com.meilai.project.entity.business.workbench.*;
import com.meilai.project.mapper.business.contract.ContractApplyMapper;
import com.meilai.project.mapper.business.customer.CustomerInfoMapper;
import com.meilai.project.mapper.business.workbench.SaleWeekTargetMapper;
import com.meilai.project.service.business.customer.CustomerFollowService;
import com.meilai.project.service.business.customer.CustomerInfoService;
import com.meilai.project.service.business.workbench.*;
import com.meilai.project.util.ThreadLocalUserUtil;
import com.meilai.project.vo.business.workbench.*;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 销售每周目标表 服务实现类
 * </p>
 *
 * @author haiYangXu
 * @since 2022-08-16
 */
@Service
public class SaleWeekTargetServiceImpl extends ServiceImpl<SaleWeekTargetMapper, SaleWeekTarget> implements SaleWeekTargetService {
    private final static BigDecimal hundred = new BigDecimal(100);

    private final static BigDecimal ten_thousand = new BigDecimal(10000);

    @Autowired
    private YearWeekService yearWeekService;

    @Autowired
    private SaleYearTargetService saleYearTargetService;

    @Autowired
    private YearService yearService;

    @Autowired
    private ContractApplyMapper contractApplyMapper;

    @Autowired
    private CustomerInfoMapper customerInfoMapper;

    @Autowired
    private CustomerInfoService customerInfoService;

    @Autowired
    private SaleWeekCustomerTargetService saleWeekCustomerTargetService;

    @Autowired
    private CustomerFollowService customerFollowService;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean add(UserYearWeekTargetDTO dto) {
        Long user_id = ThreadLocalUserUtil.get().getId();
        dto.setUser_id(user_id);
        return this.saveBatch(dto.getWeekTargetList().stream().map(item -> {
            SaleWeekTarget target = new SaleWeekTarget();
            target.setWeek_id(item.getWeek_id());
            target.setTarget_quota(item.getTarget());
            target.setUser_id(dto.getUser_id());
            target.setType(item.getType());
            return target;
        }).collect(Collectors.toList()));
    }

    @Override
    public SaleYearWeekTargetVO queryWeekList(Integer year, Integer type) {
        SaleYearWeekTargetVO vo = new SaleYearWeekTargetVO();
        vo.setType(type);
        vo.setYear(year.toString());
        Year one = yearService.getOne(Wrappers.<Year>lambdaQuery().eq(Year::getType, type).eq(Year::getYear, year));
        Long id = ThreadLocalUserUtil.get().getId();
        SaleYearTarget target = saleYearTargetService.getOne(Wrappers.<SaleYearTarget>lambdaQuery().eq(SaleYearTarget::getYear_id, one.getId()).eq(SaleYearTarget::getUser_id, id));
        vo.setSum(target.getTarget_quota());
        List<YearWeek> list = yearWeekService.list(Wrappers.<YearWeek>lambdaQuery().eq(YearWeek::getYear_id, one.getId()));
        List<BaseYearWeekVO> collect = list.stream().map(item -> {
            BaseYearWeekVO baseYearWeekVO = new BaseYearWeekVO();
            BeanUtils.copyProperties(item, baseYearWeekVO);
            baseYearWeekVO.setWeek_id(item.getId());
            return baseYearWeekVO;
        }).collect(Collectors.toList());
        vo.setWeekList(collect);
        return vo;
    }

    @Override
    public List<BaseSaleWeekTargetVO> querySaleWeekListByWeekIds(List<Long> week_ids, LocalDate month_begin, LocalDate month_end) {
        List<BaseSaleWeekTargetVO> saleWeekTargetVOList = baseMapper.querySaleCompanyTargetWeekListByWeekIds(week_ids);
        saleWeekTargetVOList.addAll(baseMapper.querySalePersonalTargetWeekListByWeekIds(week_ids));
        List<CustomerInfo> all_customer_list = customerInfoService.list(Wrappers.<CustomerInfo>lambdaQuery().isNull(CustomerInfo::getDeleted_at));
        Map<Long, List<CustomerInfo>> all_customer_map = all_customer_list.stream().collect(Collectors.groupingBy(CustomerInfo::getId));
        List<CustomerFollow> follows = customerFollowService.list(Wrappers.<CustomerFollow>lambdaQuery().le(CustomerFollow::getFollow_time, month_end).ge(CustomerFollow::getFollow_time, month_begin));
        if (CollectionUtils.isNotEmpty(saleWeekTargetVOList)) {
            List<Long> boss_ids = new ArrayList<>(Arrays.asList(BossUserEnum.values())).stream().map(BossUserEnum::getId).collect(Collectors.toList());
            // 找出时间段的目标数据
            List<SaleWeekCustomerTarget> list = saleWeekCustomerTargetService.list(Wrappers.<SaleWeekCustomerTarget>lambdaQuery().in(SaleWeekCustomerTarget::getWeek_id, week_ids));
            Map<Long, List<SaleWeekCustomerTarget>> week_target_map = list.stream().collect(Collectors.groupingBy(SaleWeekCustomerTarget::getWeek_id));
            List<Long> user_ids = saleWeekTargetVOList.stream().map(BaseSaleWeekTargetVO::getId).collect(Collectors.toList());
            user_ids.addAll(boss_ids);
            List<CustomerInfo> customerInfoList = customerInfoService.list(Wrappers.<CustomerInfo>lambdaQuery().isNull(CustomerInfo::getDeleted_at).in(CustomerInfo::getMaintenance_staff_id, user_ids));
            Map<Long, List<CustomerInfo>> user_customer_map = customerInfoList.stream().collect(Collectors.groupingBy(CustomerInfo::getMaintenance_staff_id));
            Map<Long, List<Long>> user_customer_ids_map = new HashMap<>();
            // 获取到每个人跟进的客户信息 只包含个人客户
            user_customer_map.forEach((key, value) -> user_customer_ids_map.put(key, value.stream()
                    .filter(customer -> !boss_ids.contains(customer.getPerson_in_charge_id())).map(CustomerInfo::getId).collect(Collectors.toList())));
            // 加入公司客户
            user_customer_ids_map.put(-1L, customerInfoList.stream().filter(customer -> boss_ids.contains(customer.getPerson_in_charge_id())).map(CustomerInfo::getId).collect(Collectors.toList()));
            //查询合同数据按照申请人进行分组
            Map<Long, List<ContractApply>> contract_map = contractApplyMapper.queryEffectiveContractList(month_begin, month_end, null).stream().peek(d -> {
                if (boss_ids.contains(d.getFlow_applyer_id())) d.setFlow_applyer_id(-1L);
            }).collect(Collectors.groupingBy(ContractApply::getFlow_applyer_id));
            // 计算每个人每周的签约金额和完成率
            BigDecimal zero = new BigDecimal(0).setScale(2, RoundingMode.HALF_UP);
            for (BaseSaleWeekTargetVO baseSaleWeekTargetVO : saleWeekTargetVOList) {
                // 此处如果baseSaleWeekTargetVO的id是-1为公司盘 其余的为个人
                // 获取负责的客户集合 个人获取的是本人跟进的个人客户id集合 公司盘获取的是公司客户
                List<Long> ids = user_customer_ids_map.getOrDefault(baseSaleWeekTargetVO.getId(), new ArrayList<>());
                if (CollectionUtils.isEmpty(ids)) {
                    ids.add(-1L);
                }
                // 查询此人负责的客户签约的合同数据
                List<ContractApply> applyList = contract_map.getOrDefault(baseSaleWeekTargetVO.getId(), new ArrayList<>()).stream().filter(item -> ids.contains(item.getCustomer_id())).collect(Collectors.toList());
                //过滤出符合时间段的数据
                List<ContractApply> contractApplyList = applyList.stream().filter(contract -> (contract.getSign_date().isBefore(baseSaleWeekTargetVO.getEnd_date()) || contract.getSign_date().equals(baseSaleWeekTargetVO.getEnd_date())) && (contract.getSign_date().isAfter(baseSaleWeekTargetVO.getBegin_date()) || contract.getSign_date().equals(baseSaleWeekTargetVO.getBegin_date()))).collect(Collectors.toList());
                BigDecimal count = new BigDecimal(0);
                List<WeekTransactedCustomerVO> complete_customer_list = new ArrayList<>();
                for (ContractApply contractApply : contractApplyList) {
                    count = contractApply.getDiscounted_price().add(count);
                    // todo 增加成交客户数据
                    WeekTransactedCustomerVO vo = new WeekTransactedCustomerVO();
                    vo.setId(contractApply.getCustomer_id());
                    if (all_customer_map.containsKey(contractApply.getCustomer_id())) {
                        vo.setName(all_customer_map.get(contractApply.getCustomer_id()).get(0).getName());
                    } else {
                        vo.setName("未知客户");
                    }
                    vo.setTarget(contractApply.getDiscounted_price().divide(ten_thousand, 2, RoundingMode.HALF_UP));
                    complete_customer_list.add(vo);
                }
                baseSaleWeekTargetVO.setComplete_customer_list(complete_customer_list);
                if (count.compareTo(zero) > 0) {
                    count = count.divide(ten_thousand, 2, RoundingMode.HALF_UP);
                    baseSaleWeekTargetVO.setContract_amount(count);
                    if (Convert.toBigDecimal(baseSaleWeekTargetVO.getTarget(), BigDecimal.ZERO).compareTo(zero) > 0) {
                        baseSaleWeekTargetVO.setCompletion_rate(count.divide(baseSaleWeekTargetVO.getTarget(), 2, RoundingMode.HALF_UP).multiply(hundred));
                    } else {
                        baseSaleWeekTargetVO.setCompletion_rate(zero);
                    }
                } else {
                    baseSaleWeekTargetVO.setContract_amount(zero);
                    baseSaleWeekTargetVO.setCompletion_rate(zero);
                }
                // 找出本周的目标客户数据
                List<WeekTransactedCustomerVO> target_customer_list = new ArrayList<>();
                List<SaleWeekCustomerTarget> saleWeekTargetList = week_target_map.getOrDefault(baseSaleWeekTargetVO.getWeek_id(), new ArrayList<>());
                for (SaleWeekCustomerTarget target : saleWeekTargetList) {
                    if (all_customer_map.containsKey(target.getCustomer_id())) {
                        CustomerInfo customerInfo = all_customer_map.get(target.getCustomer_id()).get(0);
                        if (baseSaleWeekTargetVO.getId() == -1L) {
                            // 如果是公司则加入公司客户
                            if (boss_ids.contains(customerInfo.getPerson_in_charge_id())) {
                                WeekTransactedCustomerVO customerVO = new WeekTransactedCustomerVO();
                                customerVO.setId(target.getCustomer_id());
                                customerVO.setTarget(target.getTarget_quota());
                                customerVO.setName(customerInfo.getName());
                                target_customer_list.add(customerVO);
                            }
                        } else {
                            // 如果是个人则加入个人客户
                            if (!boss_ids.contains(customerInfo.getPerson_in_charge_id()) && ids.contains(target.getCustomer_id())) {
                                WeekTransactedCustomerVO customerVO = new WeekTransactedCustomerVO();
                                customerVO.setId(target.getCustomer_id());
                                customerVO.setTarget(target.getTarget_quota());
                                customerVO.setName(customerInfo.getName());
                                target_customer_list.add(customerVO);
                            }
                        }
                    }
                }
                baseSaleWeekTargetVO.setTarget_customer_list(target_customer_list);
                List<BaseWeekCustomerVO> need_visit_customer_list = new ArrayList<>();
                if (baseSaleWeekTargetVO.getId() != -1) {
                    need_visit_customer_list = getNeedVisitCustomerList(null, baseSaleWeekTargetVO.getId(), baseSaleWeekTargetVO, all_customer_list, all_customer_map, follows, ids);
                } else {
                    if (CollectionUtils.isNotEmpty(boss_ids)) {
                        for (Long c : boss_ids) {
                            need_visit_customer_list.addAll(getNeedVisitCustomerList(c, null, baseSaleWeekTargetVO, all_customer_list, all_customer_map, follows, ids));
                        }
                        need_visit_customer_list = need_visit_customer_list.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(BaseWeekCustomerVO::getId))), ArrayList::new));
                        need_visit_customer_list = need_visit_customer_list.stream().sorted(Comparator.comparing(BaseWeekCustomerVO::getNext_visit_time).thenComparing(BaseWeekCustomerVO::getId)).collect(Collectors.toList());
                    }
                }
                baseSaleWeekTargetVO.setNeed_visit_customer_list(need_visit_customer_list);
            }
        }
        return saleWeekTargetVOList;
    }

    private List<BaseWeekCustomerVO> getNeedVisitCustomerList(Long person_in_charge_id, Long maintenance_staff_id, BaseSaleWeekTargetVO baseSaleWeekTargetVO, List<CustomerInfo> all_customer_list, Map<Long, List<CustomerInfo>> all_customer_map, List<CustomerFollow> follows, List<Long> ids) {
        List<BaseWeekCustomerVO> baseWeekCustomerVOS = new ArrayList<>();
        // todo 加入历史拜访客户数据
        for (CustomerInfo customerInfo : all_customer_list) {
            //
            if ((person_in_charge_id == null && customerInfo.getMaintenance_staff_id() != null && customerInfo.getMaintenance_staff_id().equals(maintenance_staff_id))
                    || (maintenance_staff_id == null && customerInfo.getPerson_in_charge_id() != null && customerInfo.getPerson_in_charge_id().equals(person_in_charge_id))
            ) {
                BaseWeekCustomerVO vo = new BaseWeekCustomerVO();
                vo.setId(customerInfo.getId());
                vo.setNext_visit_time(customerInfo.getNext_visit_time());
                if (customerInfo.getNext_visit_time() != null) {
                    vo.setName(customerInfo.getName());
                    vo.setReal_name(customerInfo.getName());
                } else {
                    vo.setName(customerInfo.getName());
                    vo.setReal_name(customerInfo.getName());
                }
                baseWeekCustomerVOS.add(vo);
            }
        }
        // 查询时间段内需要拜访的客户信息
        List<BaseWeekCustomerVO> need_visit_customer_list = baseWeekCustomerVOS.stream().filter(customer -> customer.getNext_visit_time() != null).filter(customer -> (customer.getNext_visit_time().isBefore(baseSaleWeekTargetVO.getEnd_date()) || customer.getNext_visit_time().equals(baseSaleWeekTargetVO.getEnd_date())) && (customer.getNext_visit_time().isAfter(baseSaleWeekTargetVO.getBegin_date()) || customer.getNext_visit_time().equals(baseSaleWeekTargetVO.getBegin_date()))).collect(Collectors.toList());
        // todo 加入历史拜访数据
        List<CustomerFollow> collect = follows.stream().filter(item -> (item.getFollow_time().isAfter(baseSaleWeekTargetVO.getBegin_date()) || item.getFollow_time().equals(baseSaleWeekTargetVO.getBegin_date())) && (item.getFollow_time().isBefore(baseSaleWeekTargetVO.getEnd_date()) || item.getFollow_time().equals(baseSaleWeekTargetVO.getEnd_date())) && ids.contains(item.getCustomer_id())).collect(Collectors.toList());
        List<BaseWeekCustomerVO> need_join = new ArrayList<>();
        // 找出此周期内需要拜访的客户的ids
        List<Long> customer_ids = need_visit_customer_list.stream().map(BaseWeekCustomerVO::getId).collect(Collectors.toList());
        // 过滤出此周期内有拜访记录但是再下次拜访客户中搜不到的拜访记录数据
        List<CustomerFollow> no_has_next_visit_date_list = collect.stream().filter(follow -> !customer_ids.contains(follow.getCustomer_id())).collect(Collectors.toList());
        no_has_next_visit_date_list.forEach(record -> {
            if (all_customer_map.containsKey(record.getCustomer_id())) {
                BaseWeekCustomerVO t = new BaseWeekCustomerVO();
                t.setId(record.getCustomer_id());
                t.setName(all_customer_map.get(record.getCustomer_id()).get(0).getName());
                t.setNext_visit_time(record.getFollow_time());
                t.setVisited(true);
                need_join.add(t);
            }
        });
        // 过滤出此周期内有拜访记录并且也有下次拜访客户的拜访记录数据
        List<CustomerFollow> has_next_visit_date_list = collect.stream().filter(follow -> customer_ids.contains(follow.getCustomer_id())).collect(Collectors.toList());
        // 遍历此时间段内需要拜访的客户
        // 找出是否有和下次拜访时间同一天并且是同一个客户的拜访记录 有则修改拜访状态
        need_visit_customer_list.forEach(item -> {
            List<CustomerFollow> followList = has_next_visit_date_list.stream().filter(record -> record.getCustomer_id().equals(item.getId())).collect(Collectors.toList());
            // 此周期内此客户有拜访并且和下次拜访时间重叠的
            List<CustomerFollow> collect1 = followList.stream().filter(record -> record.getFollow_time().equals(item.getNext_visit_time())).collect(Collectors.toList());
            // 此周期内此客户有拜访但是没有下次拜访时间重叠的
            List<CustomerFollow> collect2 = followList.stream().filter(record -> !record.getFollow_time().equals(item.getNext_visit_time())).collect(Collectors.toList());
            if (collect1.size() > 0) {
                item.setVisited(true);
            } else {
                item.setVisited(false);
            }
            collect2.forEach(record -> {
                if (all_customer_map.containsKey(record.getCustomer_id())) {
                    BaseWeekCustomerVO t = new BaseWeekCustomerVO();
                    t.setId(record.getCustomer_id());
                    t.setName(all_customer_map.get(record.getCustomer_id()).get(0).getName());
                    t.setNext_visit_time(record.getFollow_time());
                    t.setVisited(true);
                    need_join.add(t);
                }
            });
        });
        // 加入拜访记录数据 再进行排序
        need_visit_customer_list.addAll(need_join);
        need_visit_customer_list = need_visit_customer_list.stream().sorted(Comparator.comparing(BaseWeekCustomerVO::getNext_visit_time).thenComparing(BaseWeekCustomerVO::getId)).collect(Collectors.toList());
        return need_visit_customer_list.stream().sorted(Comparator.comparing(BaseWeekCustomerVO::getNext_visit_time)).collect(Collectors.toList());
    }

}
